﻿using Sunny.UI;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace SmartMotion.Core
{
    public partial class FrmDllFunction : UIForm
    {
        #region 字段

        private readonly DllFunction _dllFunction;
        private readonly List<string> _paraTypes;
        private readonly List<string> _paraNames;
        private List<Type> _typeList;
        //private List<MethodInfo> _funList;
        private List<string> _dllList;
        private List<Type> _allType;
        private List<Type> _searchType;

        private List<MethodInfo> _allmethods;
        private List<MethodInfo> _searchMethods;

        #endregion 字段

        public FrmDllFunction(DllFunction dllFunction)
        {
            _dllFunction = dllFunction;
            _paraTypes = new List<string>();
            _paraNames = new List<string>();
            _allType = new List<Type>();
            _searchType = new List<Type>();
            _typeList = new List<Type>();
            _allmethods = new List<MethodInfo>();
            _searchMethods = new List<MethodInfo>();
            InitializeComponent();
        }

        private void FrmDllFunction_Load(object sender, EventArgs e)
        {
            RefreshDll();
        }

        //刷新DLL，加载上一次的配置
        private void RefreshDll()
        {
            var files = Directory.GetFiles(Environment.CurrentDirectory, "*.dll");
            lsbDll.Items.Clear();
            _dllList = new List<string>();
            foreach (var file in files)
            {
                try
                {
                    Assembly curDll = Assembly.LoadFile(file);
                    var types = curDll.GetTypes();

                    if (types.Length > 0)
                    {
                        lsbDll.Items.Add(Path.GetFileName(file));
                        _dllList.Add(Path.GetFileName(file));
                    }
                }
                catch (Exception exception)
                {
                    Console.WriteLine(exception);
                }
            }

            #region 加载上一次的配置

            int index = lsbDll.Items.IndexOf(_dllFunction.Dll);
            lsbDll.SelectedIndex = index;

            foreach (var type in _typeList)
            {
                if (type.FullName == _dllFunction.TypeName)
                {
                    lsbTypes.SelectedItem = type;
                    break;
                }
            }

            foreach (var methodInfo in _allmethods)
            {
                if (methodInfo.Name == _dllFunction.MethodName)
                {
                    if (methodInfo.GetParameters().Length == _dllFunction.ParaTypes.Count)
                    {
                        lsbMethods.SelectedItem = methodInfo;
                        break;
                    }
                }
            }
            txtName.Text = _dllFunction.ItemName;

            #endregion 加载上一次的配置
        }

        //选择dll后把dll的可用类型绑定到lstType
        private void lstDll_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lsbDll.SelectedItem == null) return;
            //string fileName = Environment.CurrentDirectory + "\\" + lsbDll.SelectedItem;
            //Assembly curDll = Assembly.LoadFile(fileName);
            //_typeList = curDll.GetTypes().ToList();
            //BindingSource bs = new BindingSource();
            //bs.DataSource = _typeList;
            //lsbTypes.DataSource = bs;
            //lsbTypes.DisplayMember = "Name";

            string fileName = Environment.CurrentDirectory + "\\" + lsbDll.SelectedItem;
            var curDll = Assembly.LoadFile(fileName);
            var types = curDll.GetTypes();
            _allType = types.ToList();
            _searchType = types.ToList();
            var bs = new BindingSource();
            bs.DataSource = _searchType;
            lsbTypes.DataSource = bs;
            lsbTypes.DisplayMember = "Name";
        }

        //选择类型后把可用函数绑定到lstMethod
        private void lstType_SelectedIndexChanged(object sender, EventArgs e)
        {
            //if (lsbTypes.SelectedItem is Type tp) _funList = tp.GetMethods().ToList();
            //BindingSource bs = new BindingSource();
            //bs.DataSource = _funList;
            //lstMethod.DataSource = bs;
            //lstMethod.DisplayMember = "signature";

            var type = lsbTypes.SelectedItem as Type;
            if (type == null) return;
            _allmethods = type.GetMethods().ToList();
            _searchMethods = type.GetMethods().ToList();
            var bs = new BindingSource();
            bs.DataSource = _searchMethods;
            lsbMethods.DataSource = bs;
            lsbMethods.DisplayMember = "signature";
        }

        //选择方法后把参数名称，参数类型拿出来放到_paraNames,_paraTypes里，给保存按钮使用
        private void lstMethod_SelectedIndexChanged(object sender, EventArgs e)
        {
            var medInfo = lsbMethods.SelectedItem as MethodInfo;
            if (medInfo == null) return;

            var methodParams = medInfo.GetParameters();
            _paraNames.Clear();
            _paraTypes.Clear();

            foreach (var parameterInfo in methodParams)
            {
                _paraNames.Add(parameterInfo.Name);
                _paraTypes.Add(parameterInfo.ParameterType.FullName);
            }

            txtName.Text = medInfo.Name;
        }

        //保存一次性函数
        private void btnSave_Click(object sender, EventArgs e)
        {
            if (txtName.Text.Length == 0)
            {
                ShowErrorDialog("请输入一个名称");
                return;
            }

            _dllFunction.ItemName = txtName.Text;
            _dllFunction.Dll = lsbDll.SelectedItem.ToString();
            _dllFunction.TypeName = (lsbTypes.SelectedItem as Type)?.FullName;

            _dllFunction.MethodName = (lsbMethods.SelectedItem as MethodInfo)?.Name;
            _dllFunction.IsStatic = ((MethodInfo)lsbMethods.SelectedItem).IsStatic;
            _dllFunction.Parms.Clear();
            _dllFunction.ParaTypes.Clear();
            _dllFunction.ParaNames.Clear();
            _dllFunction.ReturnType = ((MethodInfo)lsbMethods.SelectedItem).ReturnType.FullName;
            _paraTypes.ForEach(item => _dllFunction.ParaTypes.Add(item));
            _paraNames.ForEach(item => _dllFunction.ParaNames.Add(item));
            for (int i = 0; i < _paraTypes.Count; i++)
            {
                string item = _paraTypes[i];
                _dllFunction.Parms.Add(new MethodParms() { Name = _paraNames[i], Type = item, VarSelected = false });
            }

            DialogResult = DialogResult.OK;
            Close();
        }

        //刷新DLL
        private void btnRefresh_Click(object sender, EventArgs e)
        {
            RefreshDll();
        }

        private void txtSearchDll_TextChanged(object sender, EventArgs e)
        {
            lsbDll.Items.Clear();
            string txtSearch = txtSearchDll.Text;
            foreach (var dll in _dllList.Where(dll => dll.ToLower().Contains(txtSearch.ToLower())))
            {
                lsbDll.Items.Add(dll);
            }
        }

        private void txtSearchType_TextChanged(object sender, EventArgs e)
        {
            string txtSearch = txtSearchType.Text;
            _searchType.Clear();
            foreach (var type in _allType.Where(type => type.Name.ToLower().Contains(txtSearch)))
            {
                _searchType.Add(type);
            }
            var bs = new BindingSource();
            bs.DataSource = _searchType;
            lsbTypes.DataSource = bs;
            lsbTypes.DisplayMember = "Name";
        }

        private void txtSearchMethod_TextChanged(object sender, EventArgs e)
        {
            string txtSearch = txtSearchMethod.Text;
            _searchMethods.Clear();
            foreach (var methodInfo in _allmethods)
            {
                if (methodInfo.Name.ToLower().Contains(txtSearch))
                {
                    _searchMethods.Add(methodInfo);
                }
            }
            var bs = new BindingSource();
            bs.DataSource = _searchMethods;
            lsbMethods.DataSource = bs;
            lsbMethods.DisplayMember = "signature";
        }
    }
}